/*!***************************************************
 * @file: comm_protocol.h
 * @brief: 通信协议的中层头文件，上层一般只需要包含这个头文件
 * @author: ITHAO 
 * @date: 2018.11.11
 * @note: 
 ****************************************************/
#ifndef __COMM_PROTOCOL_CORE_H__
#define __COMM_PROTOCOL_CORE_H__
#include <stdbool.h>

#include "comm_protocol.h"
/* example
    通信协议用法举例用法距离
            p_comm->data.sendfd = clientfd;
            p_comm->data.recvfd = clientfd;
            p_comm->data.send_data_packet.cmd_type = 1;
            p_comm->data.send_data_packet.cmd = 1;
            p_comm->data.send_data_packet.ack = 1;
            p_comm->data.send_data_packet.data[0] = (uint8 *)"1ST MASSGE FROM SERVER!";
            p_comm->data.send_data_packet.data[1] = (uint8 *)"2ND MASSGE FROM SERVER!";
            p_comm->data.send_data_packet.data[2] = (uint8 *)"3RD MASSGE FROM SERVER!";
            p_comm->data.send_data_packet.data[3] = (uint8 *)"4TH MASSGE FROM SERVER!";
            p_comm->data.send_data_packet.data[4] = (uint8 *)"5TH MASSGE FROM SERVER!";

            while (1) {
                p_comm->dev.cmd = COMM_SEND;
                ret = p_comm->ioctl(&p_comm->dev, 
                                        p_comm->dev.cmd, p_comm->dev.arg);
                if(ret < 0)
                    printf("send faile--ret is = %d\r\n", ret);

                p_comm->dev.cmd = COMM_RECV;
                ret = p_comm->ioctl(&p_comm->dev, 
                                    p_comm->dev.cmd, p_comm->dev.arg);
                if (ret < 0)
                    printf("recv faile ---ret is = %d \r\n", ret);

                printf("cmd_type %d \r\n", p_comm->data.recv_data_packet.cmd_type);
                printf("cmd      %d \r\n", p_comm->data.recv_data_packet.cmd);
                printf("ack      %d \r\n", p_comm->data.recv_data_packet.ack);
                int i;
                for (i = 0; i < 5; i++)
                    if(p_comm->data.recv_data_packet.data[i])
                        printf("data is %s \r\n", 
                                (char *)p_comm->data.recv_data_packet.data[i]);
 */

enum {
	NONE = 0,
    COMM_SERVER_INIT,
    COMM_CLIENT_INIT,
	COMM_SEND,
	COMM_RECV,
};

/* 存放具体操作函数的指针 */
struct comm_ops {
    int (*client_init_ops)(void);
    int (*server_init_ops)(void);
    int (*send_data_ops)(int sendfd, uint8 *data, uint16 length);
    int (*recv_data_ops)(int recvfd, uint8 **data, uint16 *length);
    int (*analy_data_ops)(struct data_packet *p_data_packet, 
                          uint8 *data, uint16 length);
    int (*package_data_ops)(struct data_packet *p_data_packet,
                            uint8 **data, uint16 *length);
};

/* 存放操作函数所用到的data */
struct comm_data {
    int recvfd;
    int sendfd;
    struct data_packet send_data_packet;
    struct data_packet recv_data_packet;
};


/*  存放core操作函数ioctl所用到的变量，
    也用于得到comm_core结构体的地址
*/
struct comm_device {
    unsigned int cmd;
	void *arg;
};

/*  通信面向对象结构体，上层所需要的操作都在这个结构体里面
    1.用的时候先将此结构体初始化
    2.将需要的参数放在对应的变量里面
    3.调用ioctl进行对应的操作
*/
struct comm_core {
    struct comm_data data;
    struct comm_ops ops;
    struct comm_device dev;
    int (*ioctl)(struct comm_device *dev,
                     unsigned int cmd, void *arg);
};


extern void comm_core_destory(struct comm_core *p_comm_core);
extern void comm_core_init(struct comm_core *p_comm_core);
extern void free_data_packet(struct data_packet *data);
extern void reset_data_packet(struct data_packet *data);
extern bool cpy_data_packet(struct data_packet *tar, 
                            struct data_packet *src);


#endif